%skeleton "lalr1.cc"
%require "2.4.1"
%defines
%define parser_class_name "DTDParser"

%code requires {
using namespace std;
#include <stack>
#include <list>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include "DTDParser.hh"
#include "StructureDTD.h"
class DTDParserDriver;
}

%parse-param { DTDParserDriver& driver }
%lex-param   { DTDParserDriver& driver }
%locations
%initial-action
{
  // Initialize the initial location.
  @$.begin.filename = @$.end.filename = &driver.file;
};

%union { 
  char *s;
  StructureEntiteDTD* dtd;
  DTDEntite* ent;
  DTDElement* elem;
  DTDEnsemble* ens;
  DTDPhrase* ph;
  DTDPhraseElement* phe;
  DTDPhraseAttlist* pha;
  DTDAttribute* attr;
  AppEntite* appent;
  vector<AppEntite>* vectE;
  vector<DTDAttribute>* vectA;
  pair<vector<AppEntite>*, int>* seq;
  int card;
}

%token TERMINATE 0
%token ELEMENT ATTLIST CLOSE OPENPAR CLOSEPAR COMMA PIPE FIXED EMPTY ANY PCDATA AST QMARK PLUS CDATA
%token <s> NAME TOKENTYPE DECLARATION STRING
%type <dtd> main dtd
%type <phe> ele_definition
%type <vectA> att_definition
%type <attr> attribut
%type <appent> item contenu
%type <ens> sequence choix sequence_ou_choix
%type <seq> liste_sequence liste_choix liste_choix_plus
%type <card> cardinalite
%type <s> att_type defaut_declaration
%code {
  #include "DTDParserDriver.h"
  #include "yydecl_dtd.h"
}

%%
main: dtd 
{
  driver.structure = $1;
}                          
;

dtd: dtd ELEMENT NAME 
     ele_definition CLOSE
{
  $$ = $1;
  $4->setElementName($3);
  $$->ajouterPhrase($4);
}
| dtd ATTLIST NAME att_definition CLOSE
{
  $$ = $1;
  DTDPhraseAttlist * phA = new DTDPhraseAttlist($3);
  for (int i = 0; i < $4->size(); i++)
  {
    phA->addAttribute($4->at(i));
  }
  $$->ajouterPhrase(phA);
}
| /* empty */ 
{ $$ = new StructureEntiteDTD; }
;

ele_definition
: EMPTY { $$ = new DTDPhraseElement(DTDElement(), 1); }
| ANY { $$ = new DTDPhraseElement(DTDElement(), 2); }
| contenu
{
  $$ = new DTDPhraseElement(DTDElement(), 0);
  $$->ajouterEnsemble(*$1);
}
;

contenu
: sequence_ou_choix cardinalite
{
AppEntite * ent = new AppEntite($1, $2);
$$ = ent;
}
;

sequence_ou_choix
: sequence { $$ = $1;}
| choix { $$ = $1;}
;

sequence
: OPENPAR liste_sequence CLOSEPAR 
{
vector<AppEntite> vectEnt;
vector<int> vectCard($2->first->size()-1, $2->second);
for (vector<AppEntite>::const_iterator it = $2->first->begin(); it != $2->first->end(); it++) {
  vectEnt.push_back(*it);
}
DTDEnsemble * ens = new DTDEnsemble(vectEnt, vectCard);
$$ = ens;
}
;

liste_sequence
: item 
{ 
$$ = new pair<vector<AppEntite>*, int>(new vector<AppEntite>, 1); 
$$->first->push_back(*$1);
}
| liste_sequence COMMA item
{
$$ = $1;
$$->first->push_back(*$3);
}
;

item
: NAME cardinalite
{
DTDElement * el = new DTDElement($1);
$$ = new AppEntite(el, $2);
}
| contenu { $$ = $1; }
| PCDATA { 
DTDElement * pcdata = new DTDElement("#PCDATA");
$$ = new AppEntite(pcdata, 0); }
;

choix
: OPENPAR liste_choix_plus CLOSEPAR
{
vector<AppEntite> vectEnt;
vector<int> vectCard($2->first->size()-1, $2->second);
for (vector<AppEntite>::const_iterator it = $2->first->begin(); it != $2->first->end(); it++) {
  vectEnt.push_back(*it);
}
DTDEnsemble * ens = new DTDEnsemble(vectEnt, vectCard);
cout << "ens : " << ens->getAffichage() << endl;
$$ = ens;
};

liste_choix_plus
: liste_choix PIPE item
{
$$ = $1;
$$->first->push_back(*$3);
}
;

liste_choix
: liste_choix PIPE item
{
$$ = $1;
$$->first->push_back(*$3);
}
| item
{ 
$$ = new pair<vector<AppEntite>*, int>(new vector<AppEntite>, 2); 
$$->first->push_back(*$1);
}
;

cardinalite
: QMARK { $$ = 3; }
| AST { $$ = 2; }
| PLUS { $$ = 1; }
| /* empty */ { $$ = 0; };
;

att_definition
: att_definition attribut
{
$$ = $1;
$$->push_back(*$2);
}
| { $$ = new vector<DTDAttribute>; }
;

attribut
: NAME att_type defaut_declaration
{
    $$ = new DTDAttribute($1, $2, $3);
}
;

att_type
: CDATA { $$ = "CDATA"; }
| TOKENTYPE { $$ = $1; }
/*| type_enumere {$$ = "NONGERE";}*/
;

/*type_enumere
: OPENPAR liste_enum_plus CLOSEPAR
;

liste_enum_plus
: liste_enum PIPE item_enum
;

liste_enum
: item_enum               
| liste_enum PIPE item_enum
;

item_enum
: NAME
;*/

defaut_declaration
: DECLARATION
| STRING
;
%%


